package com.pine.app.module.security.oauth.filter;

import com.pine.app.module.security.core.Authentication;
import com.pine.app.module.security.core.SecurityContextHolder;
import com.pine.app.module.security.core.matcher.RequestMatcher;
import com.pine.app.module.security.core.session.AuthenticationSessionStore;
import com.pine.app.module.security.core.session.impl.AuthenticationSessionStoreImpl;
import com.pine.app.module.security.core.web.BaseWebFilter;
import com.pine.app.module.security.oauth.exception.AuthenticationException;
import com.pine.app.module.security.oauth.exception.AuthenticationServerException;
import com.pine.app.module.security.oauth.provider.sso.request.HttpSessionRequestCache;
import com.pine.app.module.security.oauth.provider.sso.request.RequestCache;
import com.pine.app.module.security.oauth.provider.sso.request.SavedRequest;
import com.pine.app.module.security.oauth.provider.sso.token.OAuth2SsoTokenHandler;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author xiaoyuan
 * @create 2020/3/17 16:58
 **/
@Slf4j
public abstract class AbstractAuthenticationProcessingFilter extends BaseWebFilter {

    private RequestMatcher requestMatcher;

    private AuthenticationSessionStore authenticationSessionStore = new AuthenticationSessionStoreImpl();

    protected OAuth2SsoTokenHandler oAuth2ClientRequest;


    private RequestCache requestCache = new HttpSessionRequestCache();

    public void setRequestMatcher(RequestMatcher requestMatcher) {
        this.requestMatcher = requestMatcher;
    }

    public void setoAuth2ClientRequest(OAuth2SsoTokenHandler oAuth2ClientRequest) {
        this.oAuth2ClientRequest = oAuth2ClientRequest;
    }


    //    public AbstractAuthenticationProcessingFilter(RequestMatcher requestMatcher,
//                                                  AuthenticationSessionStore authenticationSessionStore,
//                                                  OAuth2SsoTokenHandler oAuth2ClientRequest,
//                                                  RequestCache requestCache){
//        this.requestMatcher = requestMatcher;
//        this.authenticationSessionStore  = authenticationSessionStore;
//        this.oAuth2ClientRequest = oAuth2ClientRequest;
//        this.requestCache = requestCache;
//    }




    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

         boolean    enabled  =  log.isDebugEnabled();
        if(!requestMatcher.matches(request)){
            chain.doFilter(request,response);
            return;
        }
        Authentication authentication =null;
        try{
             authentication = authentication(request,response);
            if(authentication==null){
                if(enabled){
                    log.debug("认证失败！");
                }
                SecurityContextHolder.clearContext();
                return;
            }
        }catch (AuthenticationServerException authenticationServerException){
            log.error("认证服务网络错误",authenticationServerException);
            SecurityContextHolder.clearContext();
          throw authenticationServerException;
        }catch (AuthenticationException authe){
            log.error("认证失败",authe);
            SecurityContextHolder.clearContext();
            throw authe;
        }
        authenticationSessionStore.saveAuthtication(request,authentication);
        SecurityContextHolder.setContext(authentication);
        SavedRequest savedRequest =   requestCache.getRequest(request,response);
        if(savedRequest!=null){
            response.sendRedirect(savedRequest.getRedirectUrl());
            return;
        }
        HttpServletRequest httpServletRequest =   requestCache.getMatchingRequest(request,response);
        if(httpServletRequest==null){
            httpServletRequest = request;
        }
        chain.doFilter(httpServletRequest,response);
    }

    public abstract Authentication authentication(HttpServletRequest request, HttpServletResponse response) throws IOException;
}
